package org.budo.druid.filter.timestamp;

import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.Calendar;

import org.budo.druid.filter.threadlocal.ThreadLocalFilter;
import org.budo.druid.proxy.util.PreparedStatementProxyUtil;
import org.budo.time.Time;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.alibaba.druid.filter.FilterAdapter;
import com.alibaba.druid.filter.FilterChain;
import com.alibaba.druid.proxy.jdbc.PreparedStatementProxy;
import com.alibaba.druid.proxy.jdbc.ResultSetProxy;

/**
 * @author li
 * @version 1 (2014年11月3日 上午9:27:39)
 * @since Java7
 */
public class TimestampErrorFilter extends FilterAdapter {
    private static final Logger log = LoggerFactory.getLogger(TimestampErrorFilter.class);

    public static final String DEFAULT_VALUE_NULL = "null";

    public static final String DEFAULT_VALUE_NOW = "now";

    /**
     * 默认值
     */
    private String defaultValue = DEFAULT_VALUE_NULL;

    public void preparedStatement_setTimestamp(FilterChain chain, PreparedStatementProxy statement, int parameterIndex, Timestamp x) throws SQLException {
        super.preparedStatement_setTimestamp(chain, statement, parameterIndex, x);
    }

    public void preparedStatement_setTimestamp(FilterChain chain, PreparedStatementProxy statement, int parameterIndex, Timestamp x, Calendar cal) throws SQLException {
        super.preparedStatement_setTimestamp(chain, statement, parameterIndex, x, cal);
    }

    public java.sql.Timestamp resultSet_getTimestamp(FilterChain chain, ResultSetProxy result, String columnLabel) throws SQLException {
        try {
            return chain.resultSet_getTimestamp(result, columnLabel);
        } catch (Throwable e1) {
            return this.readTimestampWhenError(chain, result, columnLabel, e1);
        }
    }

    private java.sql.Timestamp readTimestampWhenError(FilterChain chain, ResultSetProxy result, String columnLabel, Throwable e1) {
        String sql = PreparedStatementProxyUtil.getExecutableSql(ThreadLocalFilter.getPreparedStatementProxy());

        Object valueObject = null; 

        try {
            valueObject = chain.resultSet_getObject(result, columnLabel);
            String valueString = null == valueObject ? null : valueObject.toString();
            if (null == valueString || valueString.isEmpty() || "0000-00-00 00:00:00".equals(valueString)) {
                return this.defaultValue();
            }

            if (valueString.trim().length() != "0000-00-00 00:00:00".length()) { // value is not a time str
                log.error("#44 resultSet_getTimestamp error, columnLabel=" + columnLabel + ", valueString=" + valueString + ", sql=" + sql + ", e1=" + e1);
                return this.defaultValue();
            }

            return Time.when(valueString, Time.format("yyyy-MM-dd HH:mm:ss")).toTimestamp();
        } catch (Throwable e2) {
            log.error("#68 resultSet_getTimestamp error, columnLabel=" + columnLabel + ", valueObject=" + valueObject + ", sql=" + sql + ", e1=" + e1, e1);
            log.error("#69 resultSet_getTimestamp error, columnLabel=" + columnLabel + ", valueObject=" + valueObject + ", sql=" + sql + ", e2=" + e2, e2);

            return this.defaultValue();
        }
    }

    protected Timestamp defaultValue() {
        if (DEFAULT_VALUE_NULL.equalsIgnoreCase(this.getDefaultValue())) {
            return null;
        } else if (DEFAULT_VALUE_NOW.equalsIgnoreCase(this.getDefaultValue())) {
            return Time.now().toTimestamp();
        } else {
            return Time.when(this.getDefaultValue(), Time.format("yyyy-MM-dd HH:mm:ss")).toTimestamp();
        }
    }

    public String getDefaultValue() {
        return this.defaultValue;
    }

    public void setDefaultValue(String defaultValue) {
        this.defaultValue = defaultValue;
    }
}